using System;
using System.IO;
using System.Collections;
using System.Diagnostics;
using Petra.Gis.Geometry;
using Petra.Gis.Geometry.Support;
using Petra.Gis.Geometry.Utils;

namespace Petra.Gis.DataServices.SHP
{
  /// <summary>
  /// Converts a Shapefile geometry.
  /// </summary>
  partial class GeometryFactory : IGeometryFactory
  {


   /// <summary>
    /// Reads a stream and converts the shapefile record to an equilivent geometry object.
    /// </summary>
    /// <param name="file">The stream to read.</param>
    /// <param name="geometryFactory">The geometry factory to use when making the object.</param>
    /// <returns>The Geometry object that represents the shape file record.</returns>
    public static GeometryBase binaryToLineString(byte[] data)
    {
      BinaryReader br = new BinaryReader(new MemoryStream(data));

      ShapeGeometryTypes shapeType = (ShapeGeometryTypes)br.ReadInt32();
      if (!(shapeType == ShapeGeometryTypes.LineString || shapeType != ShapeGeometryTypes.LineStringM ||
               shapeType != ShapeGeometryTypes.LineStringZ))
        throw new ApplicationException("Attempting to load a non-linestring as LineString.");

      // Read and for now ignore bounds.
      //double[] box = new double[4];
      //for (int i = 0; i < 4; i++)
      //  box[i] = br.ReadDouble();
      for (int i = 0; i < 4; i++)
        br.ReadDouble();

      int[] partOffsets;
      //  Read total number of component in this geometry
      int numParts = br.ReadInt32();
      // read number of all points in this geom
      int numPoints = br.ReadInt32();

      // read geometry component offsets
      // here geometry can be MiltiLine or LineString
      // then each LineString has specified num of points
      partOffsets = new int[numParts];
      for (int i = 0; i < numParts; i++)
        partOffsets[i] = br.ReadInt32();

      // now parse LineStrings
      LineString pout;
      MultiLine maOut = new MultiLine();
      int numStringPoints = 0;
      // for all rings in blob...
      for (int RingID = 0; RingID < numParts; RingID++)
      {
        // get num of points for this linestring
        // and copy points into coordinate list
        if (numParts == 1)
          numStringPoints = numPoints;
        else
          numStringPoints = (partOffsets[RingID + 1] - partOffsets[RingID]);

        // create new linestring geom
        pout = new LineString();

        // attach coordinates
        pout.coordList = new CoordinateList(data, (int)br.BaseStream.Position, numStringPoints, Dimension.dim2D);

        // add to multiLine
        maOut.Add(pout);

      }

      if (maOut.Count > 1)
        return maOut;
      else
        return maOut[0];

    }






    public static byte[] lineStringToBinary(GeometryBase geometry)
    {

      return new byte[0];

      //GeometryCollection multi;
      //if (geometry is GeometryCollection)
      //  multi = (GeometryCollection)geometry;
      //else
      //{
      //  GeometryFactory gf = new GeometryFactory(geometry.PrecisionModel);
      //  multi = gf.CreateMultiPolygon(new Polygon[] { (Polygon)geometry });
      //}


      //BinaryWriter file = new BinaryWriter(new MemoryStream());


      //file.Write((int)ShapeGeometryTypes.Polygon);

      //BoundingBox box = multi.BoundingBox;
      //file.Write(box.Left);
      //file.Write(box.Right);
      //file.Write(box.Bottom);
      //file.Write(box.Top);

      //int numParts = GetNumParts(multi);

      //throw new NotImplementedException();
      ////int numPoints = multi.NumPoints;
      
      
      //file.Write(numParts);
      //file.Write(numPoints);

      //// write the offsets to the points
      //int offset = 0;
      //for (int part = 0; part < multi.Count; part++)
      //{
      //  // offset to the shell points
      //  Polygon polygon = (Polygon)multi[part];
      //  file.Write(offset);
      //  offset = offset + ((LineRing)polygon.Exterior).coordList.Count;

      //  // offstes to the holes
      //  foreach (LineRing ring in polygon.Holes)
      //  {
      //    file.Write(offset);
      //    offset = offset + ring.coordList.Count;
      //  }
      //}

      //// write the points 
      //for (int part = 0; part < multi.NumGeometries; part++)
      //{
      //  Polygon poly = (Polygon)multi.Geometries[part];
      //  Coordinate[] points = poly.ExteriorRing.Coordinates;
      //  WriteCoords(new CoordinateList(points), file, geometryFactory);
      //  foreach (LinearRing ring in poly.InteriorRings)
      //  {
      //    Coordinate[] points2 = ring.Coordinates;
      //    WriteCoords(new CoordinateList(points2), file, geometryFactory);
      //  }
      //}
    }








    /// <summary>
    /// Gets the length of the shapefile record using the geometry passed in.
    /// </summary>
    /// <param name="geometry">The geometry to get the length for.</param>
    /// <returns>The length in bytes this geometry is going to use when written out as a shapefile record.</returns>
    public int GetLength(LineString geometry)
    {
      throw new NotImplementedException();

      //int numParts = GetNumParts(geometry);
      //return (22 + (2 * numParts) + geometry.NumPoints * 8);
    }





  }
}
